﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UMC.Data;
using UMC.ITME.Entities;
using UMC.Net;
using UMC.SshNet.Common;

namespace UMC.ITME
{
    class HttpMimeContext : UMC.Net.NetContext
    {
        public override void SignOut()
        {
            base.SignOut();

            var sessionKey = Utility.Guid(Utility.NewGuid());
            var cdmn = WebServlet.MainDomainValue;
            var cdm = cdmn;
            if (WebServlet.DomainUnion == '-')
            {
                cdm = cdmn.Slice(cdmn.Span.IndexOf((byte)'.'));
            }

            if (this.Scheme.Span.SequenceEqual(StringValue.Https.Span))
            {
                if (this.Host.Span.EndsWith(cdm.Span))
                {
                    this.AddHeader(new HeadValue(StringValue.SetCookie, this.Memory.Rent($"{WebServlet.SessionCookieName}={sessionKey}; SameSite=None; Secure; Expires={DateTime.Now.AddYears(10):r}; HttpOnly; Domain={cdm}; Path=/")));
                }
                else
                {
                    this.AddHeader(new HeadValue(StringValue.SetCookie, this.Memory.Rent($"{WebServlet.SessionCookieName}={sessionKey}; SameSite=None; Secure; HttpOnly; Path=/")));
                }
            }
            else
            {
                if (this.Host.Span.EndsWith(cdm.Span))
                {
                    this.AddHeader(new HeadValue(StringValue.SetCookie, this.Memory.Rent($"{WebServlet.SessionCookieName}={sessionKey}; Expires={DateTime.Now.AddYears(10):r}; HttpOnly; Domain={cdm}; Path=/")));
                }
                else
                {
                    this.AddHeader(new HeadValue(StringValue.SetCookie, this.Memory.Rent($"{WebServlet.SessionCookieName}={sessionKey}; HttpOnly; Path=/")));
                }
            }

        }
        public override void AddHeader(StringValue name, string value)
        {
            _response.AddHeader(new HeadValue(name, this.Memory.Rent(value)));
        }
        public override ByteChunk Memory => _request.Memory;
        public override string Server => Environment.MachineName;
        HttpMimeRequest _request;
        HttpMimeResponse _response;
        public override long? ContentLength { get => _request.ContentLength; set => _response.ContentLength = value; }
        public override void AppendCookie(string name, string value)
        {
            this.AppendCookie(name, value, "/");

        }
        public override void NotCounted()
        {
            _request.NotCounted();
        }
        public override void OutputHeaded(Action action)
        {
            _response.Headed = action;
        }

        public override void AppendCookie(string name, string value, string path)
        {
            if (UMC.Web.WebServlet.SessionCookieName.Span.SequenceEqual(name.UTF8()))
            {

                _response.AddHeader(new HeadValue(StringValue.SetCookie, _request.Memory.Rent($"{name}={value}; Expires={DateTime.Now.AddYears(10):r}; Path={path}")));

            }
            else
            {
                _response.AddHeader(new HeadValue(StringValue.SetCookie, _request.Memory.Rent($"{name}={value}; Path={path}")));
            }
        }
        public override bool IsWebSocket => _request.IsWebSocket;
        Net.TextWriter writer;

        public override void RewriteUrl(string pathAndQuery)
        {
            _request.RewriteUrl(new StringValue(pathAndQuery));
            _QueryString = null;
        }
        public HttpMimeContext(HttpMimeRequest request, HttpMime mime)
        {
            this._request = request;
            this._response = new HttpMimeResponse(request, mime.Write, request.netLoger);
            this.Tag = request._context.Tag;
            this.writer = new Net.TextWriter(_response.OutputStream.Write);
        }
        public override void ReadAsData(NetWriteData readData)
        {
            if (_request.ContentLength > 0 && _request.IsMimeFinish == false)
            {
                aseSynchronousIOEnd = true;
            }
            this._request.ReadAsData(this.Token?.IsMonitor == true, readData);
        }
        bool aseSynchronousIOEnd;

        public override void UseSynchronousIO()
        {
            aseSynchronousIOEnd = true;
        }

        public override NetLoger Loger => _request.netLoger;
        public override void OutputFinish()
        {

            this.Output.Flush();
            if (_response.OutputFinish())
            {
                _request._context.OutputFinish();
            }
            else
            {
                _request._context.Stop();
            }

            if (aseSynchronousIOEnd)
                WriteLog();
            _request.Dispose();

        }
        void WriteLog()
        {

            if (this.Token != null)
            {
                if (this.Token.IsAuthenticated)
                {
                    var username = this.Token.Username;
                    if (String.IsNullOrEmpty(username) || String.Equals(username, "?") || String.Equals(username, "#"))
                    {
                        _request.netLoger.Write(HttpLogerType.Username, Utility.Guid(this.Token.UserId.Value));
                    }
                    else
                    {
                        _request.netLoger.Write(HttpLogerType.Username, username);
                    }
                }
            }


            _request._context.WriteLog(_request.startTime, _request.netLoger);

        }
        public void AllowFingerprint()
        {
            if (_request._context is HttpsMimeSocket)
            {
                HttpsMimeSocket httpsMime = (HttpsMimeSocket)_request._context;

                HotCache.Put(new Firewall
                {
                    Fingerprint = httpsMime.tlsSite1.Finger,
                    AuthType = AuthType.Allow,
                    Expire = Utility.TimeSpan(DateTime.Now.AddDays(30)),
                    Type = 2
                });
            }
        }

        public override void Error(Exception ex)
        {
            this.Output.Flush();
            _response.OutputError(ex);
            WriteLog();
            _request._context.Stop();
            _request.Dispose();

        }
        public override void ReadAsForm(Action<HeadValues> action)
        {
            if (_request.ContentLength > 0 && _request.IsMimeFinish == false)
            {

                aseSynchronousIOEnd = true;

            }


            _request.ReadAsForm(this.Token?.IsMonitor == true, a =>
            {
                try
                {
                    action?.Invoke(a);
                }
                catch (Exception ex)
                {
                    Error(ex);

                }
            });
        }
        public virtual void ProcessRequest()
        {
            HttpMimeServier.Current.Handler().ProcessRequest(this);//  new UMC.ITME.WebServlet().ProcessRequest(this);
        }
        internal protected virtual void ProcessAfter()
        {
            if (this.IsWebSocket == false && aseSynchronousIOEnd == false)
            {
                this.Output.Flush();
                _response.OutputFinish();
                _request._context.OutputFinish();
                WriteLog();
                _request.Dispose();
            }
        }
        public override int StatusCode
        {
            get
            {
                return this._response.StatusCode;
            }
            set
            {
                this._response.StatusCode = value;
            }
        }
        public override void AddHeader(string name, string value)
        {
            this._response.AddHeader(name, value);
        }
        HeadValues _QueryString;
        public override HeadValues QueryString
        {
            get
            {
                if (_QueryString == null)
                {
                    if (this.Query.IsEmpty == false)
                    {
                        _QueryString = new HeadValues(true);
                        var s = Query;
                        var span = s.Span;
                        var size = span.Length;
                        StringValue key = StringValue.Empty;
                        int start = 1;
                        for (int i = 1; i < size; i++)
                        {
                            switch (span[i])
                            {
                                case 0x26:
                                    _QueryString.Add(new HeadValue(key, s.Slice(start, i - start)));
                                    start = i + 1;
                                    break;
                                case 0x3d:
                                    key = s.Slice(start, i - start);
                                    start = i + 1;
                                    break;
                            }
                        }
                        if (start < size)
                        {
                            _QueryString.Add(new HeadValue(key, s.Slice(start, size - start)));
                        }
                    }
                    else
                    {
                        _QueryString = new HeadValues();
                    }
                }
                return _QueryString;
            }
        }

        public override  UMC.Net.TextWriter Output
        {
            get
            {
                return this.writer;
            }
        }
        public override System.IO.Stream OutputStream
        {
            get
            {
                return this._response.OutputStream;
            }
        }
        public override StringValue Path => _request.Path;// throw new NotImplementedException();
        public override StringValue Query => _request.Query;// throw new NotImplementedException();
        public override StringValue Scheme => _request._scheme;
        // String _ContentType;
        public override StringValue ContentType
        {
            get
            {

                return this._request.ContentType;
            }
            set
            {
                this._response.ContentType = value;
            }
        }

        public override string UserHostAddress
        {
            get { return this._request.UserHostAddress; }
        }

        public override StringValue RawUrl
        {
            get { return _request.Second; }
        }
        public override StringValue UserAgent
        {
            get { return this._request._UserAgent; }
        }
        public override Uri UrlReferrer
        {
            get
            {
                return _request.UrlReferrer;

            }
        }

        public override Uri Url
        {
            get { return _request.Url; }
        }

        public override void Redirect(string url)
        {
            this._response.Redirect(this.Memory.Rent(url));
        }

        public override void Redirect(StringValue url)
        {
            this._response.Redirect(url);
        }

        public override void AddHeader(HeadValue head)
        {
            this._response.AddHeader(head);

        }
        public override HttpMethod Method
        {
            get { return this._request.HttpMethod; }
        }

        public override StringValue Host => this._request._host;

        public override StringValue PathQuery => this._request.PathQuery;

        public override HeadValues Headers => this._request.Headers;

        public override HeadValues Cookies => this._request.Cookies;
    }
}
